'use strict';


const moment = require('moment')


const Controller = require('egg').Controller;
class BillController extends Controller {

    // 获取首页列表数据
    async list() {
        const { ctx, app } = this

        // 从前端传过来的参数中，拿到页数、时间、类型
        // 前端发的是 get 请求， post 请求用 ctx.request.body 获取参数 是因为 post 请求将参数放在 body 里面。
        // 而 get 请求会将参数放在 url 里面
        // console.log(ctx.query); //{ page: '1', page_size: '5', date: '2021-11', type_id: 'all' }
        const { date, page, page_size = 5, type_id = 'all' } = ctx.query

        //
        try {
            let user_id;
            // 拿到 token 
            const token = ctx.request.header.authorization

            // 检验一下 token 的正确性
            const decode = await app.jwt.verify(token, app.config.secret)
            // console.log('在bill页面获取信息时token检验后的一些信息',decode);    //{ id: 4, username: 'aaa', exp: 1636265781, iat: 1636179381 }

            user_id = decode.id

            if (!decode) {
                console.log('token检验失败,id获取失败');
                return
            }


            // 那么就拿着user_id去数据库中找符合要求的数据
            const list = await ctx.service.bill.list(user_id)
            // console.log('这里是bill页面拿到的账单详细', list);  //成功拿到了


            // 虽然拿到了数据，但是要规划好向前端怎么返回数据

            // 注意过滤月份
            const _list = list.filter(item => {
                // 不是全部类型的数据。那么就要筛选返回
                if (type_id != 'all') {
                    // 如果不是 all ，筛选 type_id 
                    // 返回前端需要的类型的账单
                    // return item.type_id == type_id


                    // 使用 moment ，先将后端时间标准化，再比较
                    return moment(Number(item.date)).format('YYYY-MM') == date && type_id == item.type_id
                } else {
                    // 只要时间能对上，就输出
                    return moment(Number(item.date)).format('YYYY-MM') == date
                }
            })




            // 格式化
            let listMap = _list.reduce((curr, item) => {
                const date = moment(Number(item.date)).format('YYYY-MM-DD')

                // 如果能在累加的数组中找到当前项日期的，那么在数组中的加入当前项到 bills 数组。
                if (curr && curr.length && curr.findIndex(item => item.date == date) > -1) {
                    const index = curr.findIndex(item => item.date == date)
                    curr[index].bills.push(item)
                }
                // 如果在累加的数组中找不到当前项日期的，那么再新建一项。
                if (curr && curr.length && curr.findIndex(item => item.date == date) == -1) {
                    curr.push({
                        date,
                        bills: [item]
                    })
                }

                if (!curr.length) {
                    curr.push({
                        date,
                        bills: [item]
                    })
                }
                return curr
            }, []).sort((a, b) => moment(b.date) - moment(a.date))




            // 前端有上拉加载更多
            // 后端写一下分页

            // 重新构建了数组结构
            const filterListMap = listMap.slice((page - 1) * page_size, page * page_size)       //假如前端传过来的是1，则切割出 0-5条数据，也就是第一页的数据

            // 过滤出来当前数组里面时间与前端时间一致的数据
            let __list = list.filter(item => moment(Number(item.date)).format('YYYY-MM-DD'))

            // 将总体支出和总体收入返回给前端
            let totalExpense = __list.reduce((curr, item) => {
                if (item.pay_type == 1) {
                    curr += Number(item.amount)
                    return curr
                }
                return curr
            }, 0)
            let totalIncome = __list.reduce((curr, item) => {
                if (item.pay_type == 2) {
                    curr += Number(item.amount)
                    return curr
                }
                return curr
            }, 0)






            ctx.body = {
                code: 200,
                msg: '请求成功',
                data: {
                    totalExpense,
                    totalIncome,
                    totalPage: Math.ceil(listMap.length / page_size),
                    list: filterListMap || []
                }
            }

        } catch (error) {
            ctx.body = {
                code: 500,
                msg: '系统错误+++',
                data: null
            }
            console.log(error);
        }



        // 这里是之前写的假数据，现在写好了上面的请求数据，就不用它了
        // ctx.body = {
        //     code: 200,
        //     msg: "请求成功",
        //     data: {
        //         "totalExpense": 300,
        //         "totalIncome": 0,
        //         "totalPage": 1,
        //         "list": [{
        //             "date": "2021-10-30",
        //             "bills": [{
        //                 "id": 2691,
        //                 "pay_type": 1,
        //                 "amount": "200.00",
        //                 "date": "1635581598000",
        //                 "type_id": 2,
        //                 "type_name": "服饰",
        //                 "remark": ""
        //             }, {
        //                 "id": 2692,
        //                 "pay_type": 1,
        //                 "amount": "100.00",
        //                 "date": "1635584652000",
        //                 "type_id": 5,
        //                 "type_name": "购物",
        //                 "remark": ""
        //             }]
        //         }]
        //     }
        // }
    }



    // 获取到账单详情
    async getDetail() {
        // 取下传入的参数 id
        const { ctx, app } = this
        let { id = '' } = ctx.query
        // 获取到用户id
        let user_id
        const token = ctx.request.header.authorization;
        const decode = await app.jwt.verify(token, app.config.jwt.secret)
        if (!decode) return
        user_id = decode.id
        if (!id) {
            ctx.body = {
                code: 500,
                msg: '账单id不能为空!',
                data: null
            }
            return
        }
        console.log('到达获取账单的后台逻辑，准备拿着id取bill数据', id, user_id);
        try {
            // 拿着id准备找账单详细信息
            const data = await ctx.service.bill.findBill(id, user_id)
            console.log('查询到的账单详情', data);
            ctx.body = {
                code: 200,
                msg: '查询账单成功',
                data: data
            }
            return
        } catch (error) {
            console.log('查询账单失败', error);
            ctx.body = {
                code: 500,
                msg: '查询账单失败',
                data: null
            }
            return
        }
    }




    // 获取可视化所需数据
    // 获取总支出/收入 数据
    async getAllNumber() {

        // 注意！这个请求可能与后续的可视化条形表有关联，届时的请求多一条时间筛选项
        // 目前不知道怎么结合，因此先写总收入/支出的请求
        const { app, ctx } = this
        const { pay_type } = ctx.request.query





        const token = ctx.request.header.authorization;
        const decode = await app.jwt.verify(token, app.config.jwt.secret)
        // 用户id，必须是对应用户的数据
        let user_id = decode.id
        if (!user_id) {
            ctx.body = {
                code: 500,
                msg: '用户id不能为空',
                data: null
            }
            return
        }
        console.log('获取到用户id和请求类型，准备获取总收入/总支出的数据', pay_type, user_id);




        if (pay_type) {
            // 请求总支出数据
            try {
                const data = await ctx.service.bill.findAll(pay_type, user_id)
                if (data) {
                    ctx.body = {
                        code: 200,
                        msg: '请求成功',
                        data: data
                    }
                }
            } catch (error) {
                console.log('请求总支出/总收入失败', error);
                ctx.body = {
                    code: 500,
                    msg: '请求总支出/总收入失败',
                    data: null
                }
                console.log(error);
            }
        }
    }


    // 增加新账单
    async addBill() {
        const { app, ctx } = this
        const { newBill } = ctx.request.body
        console.log('看看增加新账单时前端传入的数据', newBill);

        // 获取到用户id
        const token = ctx.request.header.authorization
        const decode = await app.jwt.verify(token, app.config.jwt.secret)
        let user_id = decode.id

        const new_bill = {
            ...newBill,
            user_id
        }
        try {
            // 一个账单所需数据准备完毕，开始建立新账单
            const data = await ctx.service.bill.addNewBill(new_bill)
            console.log('看看是否创建新账单成功', data);
            if (data) {
                ctx.body = {
                    code: 200,
                    msg: '新账单创建成功',
                    data: data
                }
            }
        } catch (error) {
            console.log('在创建新账单的后端出错', error);
            return
        }
    }


    // 删除账单
    async deleteBill() {
        const { ctx, app } = this
        const { id = '' } = ctx.query

        const token = ctx.request.header.authorization
        const decode = await app.jwt.verify(token, app.config.jwt.secret)
        let user_id = decode.id
        if (!user_id) {
            ctx.body = {
                code: 500,
                msg: '用户未登入',
                data: null
            }
        }


        try {
            const data = await ctx.service.bill.deleteOneBill(id, user_id)
            console.log('查看是否删除账单', data);
            if (data) {
                ctx.body = {
                    code: 200,
                    msg: '删除成功',
                    data: data
                }
                return
            }
            return
        } catch (error) {
            console.log('删除账单失败', error);
            return
        }





    }


    // 获取到总收入/总支出
    async data() {
        const { ctx, app } = this
        const { date = '' } = ctx.query

        // 获取到用户id
        const token = ctx.request.header.authorization
        const decode = await app.jwt.verify(token, app.config.jwt.secret)
        if (!decode) return
        let user_id = decode.id

        if (!date) {
            ctx.body = {
                code: 400,
                msg: '前端未传递请求时间',
                data: null
            }
            return
        }
        try {

            const result = await ctx.service.bill.list(user_id)
            // 返回了该用户的全部的账单
            console.log('查看数据库操作向后端返回了什么', result);
            // 然后在后端根据时间，进行筛选返回
            //操作Date类型数据
            const start = moment(date).startOf('month').unix() * 1000 //选择月份，月初时间
            const end = moment(date).endOf('month').unix() * 1000     //选择月份，月末时间
            console.log('查看时间差', Math.ceil((end - start) / (1000 * 60 * 60 * 24)));
            const sumDate = Math.ceil((end - start) / (1000 * 60 * 60 * 24))    //该月总天数
            const _data = result.filter(item => {
                // 符合条件的数据
                if (Number(item.date) > start && Number(item.date) < end) {
                    return item
                }
            })

            // 深拷贝一个data，并且将他的date进行更改
            const other_data = JSON.parse(JSON.stringify(_data)).map(item => {
                item.date = new Date(item.date - 0).getDate()
                return item
            });


            // 总支出
            const total_expense = _data.reduce((arr, cur) => {
                if (cur.pay_type == 1) {
                    arr += Number(cur.amount)
                }
                return arr
            }, 0)

            // 总支出的平均数
            const total_expense_mean = (total_expense / sumDate).toFixed(2)
            // 总收入
            const total_income = _data.reduce((arr, cur) => {
                if (cur.pay_type == 2) {
                    arr += Number(cur.amount)
                }
                return arr
            }, 0)
            // 总收入的平均数
            const total_income_mean = (total_income / sumDate).toFixed(2)

            // 获取收支构成
            let total_data = _data.reduce((arr, cur) => {
                // 之前是否出现过这个类型的数据，出现过的话，记下它在数组中的位置
                const index = arr.findIndex(item => item.type_id == cur.type_id)
                if (index == -1) {
                    // 创建新类型
                    arr.push({
                        type_id: cur.type_id,
                        type_name: cur.type_name,
                        pay_type: cur.pay_type,
                        number: Number(cur.amount)
                    })
                }

                // 之前出现过这个类型的数据
                if (index > -1) {
                    // 将他们的金额合并
                    arr[index].number += Number(cur.amount)
                }

                return arr
            }, [])

            // 整理数据
            total_data = total_data.map(item => {
                item.number = Number(Number(item.number).toFixed(2))
                return item
            })

            // 按时间进行排序，用于折线图的展示
            // 进行总和，将同一天的数据存储到一起
            const time_data = other_data.reduce((arr, cur) => {
                // 存储的内容中是否出现过这一天
                const index = arr.findIndex(item => item.date == cur.date)
                if (index == -1) {
                    // 创建新天数
                    arr.push({
                        date: cur.date,
                        show: [
                            {
                                id: cur.id,
                                type_id: cur.type_id,
                                type_name: cur.type_name,
                                pay_type: cur.pay_type,
                                number: Number(cur.amount),
                            }
                        ]
                    })
                }

                // 之前录入了这天
                if (index > -1) {
                    // 存入这条数据
                    arr[index].show.push({
                        id: cur.id,
                        type_id: cur.type_id,
                        type_name: cur.type_name,
                        pay_type: cur.pay_type,
                        number: Number(cur.amount),
                    })
                }
                return arr
            }, [])




            console.log('检查整理后的时间', time_data);



            ctx.body = {
                code: 200,
                msg: '请求成功',
                data: {
                    total_expense: Number(total_expense).toFixed(2),    // 总支出
                    total_income: Number(total_income).toFixed(2),      // 总收入
                    total_data: total_data || [],           //整理后的条形可视化所需数据
                    total_expense_mean: total_expense_mean,  // 总支出的平均数
                    total_income_mean: total_income_mean,    // 总收入的平均数
                    time_data:time_data,                    //准备好的折线图数据
                    sumDate:sumDate,                        //该月的总天数
                }
            }
        } catch (error) {
            ctx.body = {
                code: 500,
                msg: '请求总数据错误',
                data: null
            }
            console.log('请求总数据错误', error);
        }



    }



}

module.exports = BillController;
